#include "TimelineObject.h"
#include "LightAbstractRenderer.h"
#include "As2Variable.h"


namespace LightPlayer{


	TimelineObject::TimelineObject(){
		init();
	}


	void TimelineObject::init(){
		SceneObject::init();
		m_Stream.init();
		clearDisplayList();
		m_ActionList.clear();
		m_FrameLabelList.clear();
		m_ActualFrame = 0;
		m_FrameCount = 0;
		m_IsPlaying = true;
		m_Visible = true;

		m_pParent = NULL;
		m_pCharacterList = NULL;
		m_pObjectPool = NULL;
		m_pTimelineObjectPool = NULL;
		m_pAs2VM = NULL;
		m_VarList.clear();
	}

	void TimelineObject::SetParent( Parser* pParent ){
		if( m_pParent != pParent ){
			m_pParent = pParent;
			if(m_pParent){
				SetCharacterList( m_pParent->getCharacterList() );
				SetObjectPool( m_pParent->getObjectPool() );
				SetTimelineObjectPool( m_pParent->getTimelineObjectPool() );
				SetAs2VM( m_pParent->getAs2VM() );
			}
			else{
				SetCharacterList( NULL );
				SetObjectPool( NULL );
				SetTimelineObjectPool( NULL );
				SetAs2VM( NULL );
			}
		}
	}

	void TimelineObject::setCharacter( Character* character ){
		if( getCharacter() != character ){
			// is new character
			clearDisplayList();
			SceneObject::setCharacter( character );
			if( character ){
				assert( character->getType() == eSpriteCharacter );
				SPRITE_DEFINITION* spr = (SPRITE_DEFINITION*)character;

				m_Stream = spr->m_ControlTags;
				m_FrameCount = spr->m_FrameCount;
				m_ActualFrame = 0;
				
				collectFrameLabels();
				firstUpdate();
			}
		}
	}

	void TimelineObject::update( float dt ){
		Parser::update(dt);
	}

	void TimelineObject::draw( LightAbstractRenderer* pRenderer ){
		pRenderer->pushMatrix( m_Transform );
		pRenderer->pushCXFORM( m_ColorTransfom );

		m_DsiplayList.draw( pRenderer );

		pRenderer->popCXFORM();
		pRenderer->popMatrix();
	}

	SceneObject* TimelineObject::getNewSceneObject(){
		if(m_pObjectPool){
			SceneObject* obj = m_pObjectPool->getNew();
			obj->init();
			return obj;
		}
		return NULL;
	}

	TimelineObject* TimelineObject::getNewTimelineObject(){
		if(m_pTimelineObjectPool){
			TimelineObject* obj = m_pTimelineObjectPool->getNew();
			obj->init();
			return obj;
		}
		return NULL;
	}

	void TimelineObject::freeObject( SceneObject* object ){
		if(object && object->getType() == eSceneObject && m_pObjectPool ){
			object->init();
			m_pObjectPool->FreeObject( object );
		}
		else if(object && object->getType() == eTimelineObject && m_pTimelineObjectPool ){
			TimelineObject* timeline = (TimelineObject* )object;
			timeline->init();
			m_pTimelineObjectPool->FreeObject( timeline );
		}
		else{
			assert(0);
		}
	}

	void TimelineObject::clearDisplayList(){
		display_list_type::iterator it = m_DsiplayList.list.begin();
		for (; it != m_DsiplayList.list.end(); ++it ){
			freeObject( it->second );
		}
		m_DsiplayList.clear();
	}

	void TimelineObject::collectFrameLabels(){
		m_FrameLabelList.clear();

		Stream strCpy = m_Stream;
		strCpy.rewind();

		uint16 cur_frame = 1;
		TAG tag;
		do{
			tag.readFromStream( &strCpy );

			if( tag.type == eShowFrame ){
				cur_frame++;
			}

			if( tag.type == eFrameLabel ){
				const char* label = (const char*) strCpy.getCurrentPosition();
				m_FrameLabelList.push_back( type_label_list(label,cur_frame) );
			}

			strCpy.skip_byte( tag.size );
		} while ( tag.type != eEnd );
	}

	uint16 TimelineObject::getFrameForLabel( const char* label ){
		FrameLabelList::iterator it = m_FrameLabelList.begin();
		for (; it != m_FrameLabelList.end(); ++it){
			if( strcmp( it->first, label ) == 0 ){
				return it->second;
			}
		}
		return 0;
	}

	As2Var TimelineObject::getVar( const char* name ){
		string nameKey = name;
		if( m_VarList.find( nameKey ) != m_VarList.end() ){
			return m_VarList[nameKey];
		}
		return As2Var();
	}

	void TimelineObject::setVar( const char* name, const As2Var& value ){
		string nameKey = name;
		m_VarList[nameKey] = value;
	}

	As2Var TimelineObject::getProperty( PropertyEnum property ){
		As2Var return_value;
		return_value.set_undef();
		switch( property ){
		default: break;
		case _X:					{ return_value.set_float(	m_Transform.getX()						);				break; }
		case _Y:					{ return_value.set_float(	m_Transform.getY()						);				break; }
		case _xscale:				{ return_value.set_float(	m_Transform.getScaleX() * 100.0f		);				break; }
		case _yscale:				{ return_value.set_float(	m_Transform.getScaleY()	* 100.0f		);				break; }
		case _currentframe:			{ return_value.set_int(		m_ActualFrame							);				break; }
		case _totalframes:			{ return_value.set_int(		m_FrameCount							);				break; }
		case _alpha:				{ return_value.set_float(	m_ColorTransfom._MultA * 100.0f			);				break; }
		case _visible:				{ return_value.set_bool(	m_Visible								);				break; }
		case _width:				{ return_value.set_float(	getBounds().width()						);				break; }
		case _height:				{ return_value.set_float(	getBounds().height()					);				break; }
		case _rotation:				{ return_value.set_float(	RADIANS_TO_DEGREES(m_Transform.getRotation() )	);		break; }
		case _target:				{ return_value.set_str(		s_empty_string							);				break; }
		case _framesloaded:			{ return_value.set_int(		m_FrameCount							);				break; }
		case _name:					{ return_value.set_str(		m_Name ? m_Name : s_empty_string		);				break; }
		case _droptarget:			{ return_value.set_str(		s_empty_string							);				break; }
		case _url:					{ return_value.set_str(		s_empty_string							);				break; }
		case _highquality:			{ return_value.set_bool(	true									);				break; }
		case _focusrect:			{ return_value.set_float(	0.0f									);				break; }
		case _soundbuftime:			{ return_value.set_float(	0.0f									);				break; }
		case _quality:				{ return_value.set_int(		1										);				break; }
		case _xmouse:				{ return_value.set_float(	0.0f									);				break; }
		case _ymouse:				{ return_value.set_float(	0.0f									);				break; }
		}
		return return_value;
	}

	void TimelineObject::setProperty(PropertyEnum property, const As2Var& value ){
		switch( property ){
		default: break;
		case _X:					{ m_Transform.setX( value.getAsFloat() );	m_LockByActionScript = true;									break; }
		case _Y:					{ m_Transform.setY( value.getAsFloat() );	m_LockByActionScript = true;									break; }
		case _xscale:				{ m_Transform.setScaleX( value.getAsFloat() / 100.0f );	m_LockByActionScript = true;						break; }
		case _yscale:				{ m_Transform.setScaleY( value.getAsFloat() / 100.0f );	m_LockByActionScript = true;						break; }
		case _currentframe:			{ /*read only by flash doc*/																				break; } 
		case _totalframes:			{ /*read only by flash doc*/																				break; } 
		case _alpha:				{ m_ColorTransfom._MultA = value.getAsFloat() / 100.0f;	m_LockByActionScript = true;						break; }
		case _visible:				{ m_Visible = value.getAsBool();																			break; }
		case _width:				{ setWidth( value.getAsFloat() );	m_LockByActionScript = true;											break; }
		case _height:				{ setHeight( value.getAsFloat() );	m_LockByActionScript = true;											break; }
		case _rotation:				{ m_Transform.setRotation( DEGREES_TO_RADIANS(value.getAsFloat() ) );  m_LockByActionScript = true;			break; }
		case _target:				{ /*read only by flash doc*/																				break; } 
		case _framesloaded:			{ /*read only by flash doc*/																				break; } 
		case _name:					{ m_As2Name = value; m_Name = m_As2Name.getAsString();														break; }
		case _droptarget:			{ /*read only by flash doc*/																				break; } 
		case _url:					{ /*read only by flash doc*/																				break; } 
		case _highquality:			{ 																											break; }
		case _focusrect:			{ 																											break; }
		case _soundbuftime:			{ 																											break; }
		case _quality:				{ 																											break; }
		case _xmouse:				{ /*read only by flash doc*/																				break; } 
		case _ymouse:				{ /*read only by flash doc*/																				break; } 
		}
	}

	void TimelineObject::cloneFromObject( TimelineObject* object, const char* name, uint16 depth, Parser* parent /*= NULL*/  ){
		init();
		SetParent( parent ? parent : object->getParent() );
		setCharacter( object->getCharacter() );

		this->m_Depth = depth;
		this->m_Name = name;

		this->m_Transform = object->m_Transform;
		this->m_ColorTransfom = object->m_ColorTransfom;
		this->m_MorphRatio = object->m_MorphRatio;
		this->m_ClipDepth = object->m_ClipDepth;
		// clip action : TO DO
	}

	RECT TimelineObject::getBounds() const
	{
		RECT bounds;
		RECT temp;

		display_list_type::const_iterator it = m_DsiplayList.list.begin();
		for (; it != m_DsiplayList.list.end(); ++it ){
			if( it->second ){
				temp = it->second->getBounds();
				if(! temp.isNull() ){
					temp.transform( m_Transform );
					bounds.extend( temp );
				}
			}
		}

		return bounds;
	}

	void TimelineObject::setWidth(float _width)
	{
		float actual_width = getBounds().width();
		actual_width /= m_Transform.getScaleX();
		float new_scale = _width / actual_width;
		m_Transform.setScaleX( new_scale );
	}

	void TimelineObject::setHeight(float _height)
	{
		float actual_height = getBounds().height();
		actual_height /= m_Transform.getScaleY();
		float new_scale = _height / actual_height;
		m_Transform.setScaleY( new_scale );
	}

};